
package com.yuanmei.datas;

import android.util.Log;

import com.yuanmei.model.HistoryDayQuote;
import com.yuanmei.model.StockInfo;
import com.yuanmei.common.Utils;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmResults;
import io.realm.Sort;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

// curl -X POST -d '{"api_name": "daily", "token": "55189c3a5c7c0cf86a7b738f5e3537414f3c250f072b7005dfbd70b6",
// "params": {"ts_code":"000001.SZ", "start_date":"20180901", "end_date":"20181001"}}' http://api.tushare.pro
/*
$ curl -X POST -d '{"api_name": "daily", "token": "55189c3a5c7c0cf86a7b738f5e3537414f3c250f072b7005dfbd70b6", "params": {"ts_code":"000001.SZ", "start_date":"20180912", "end_date":"20180914"}}' http://api.tushare.pro
{"request_id": "1943e5ac091d11e9b34ed00dd36710041545835619409271", "code": 0, "msg": null, "data": {"fields": ["ts_code", "trade_date", "open", "high", "low", "close", "pre_close", "change", "pct_chg", "vol", "amount"], "items": [["000001.SZ", "20180914", 9.9800, 9.9800, 9.8100, 9.8400, 9.9600, -0.1200, -1.2048, 619750.190000, 611422.480000], ["000001.SZ", "20180913", 10.0900, 10.1000, 9.8400, 9.9600, 9.8800, 0.0800, 0.8097, 999725.610000, 993389.970000], ["000001.SZ", "20180912", 9.8700, 9.9700, 9.8200, 9.8800, 9.9100, -0.0300, -0.3027, 564829.160000, 558399.563000]]}}

*/

class TuShareProSource {
    private static final String TAG = TuShareProSource.class.getName();

    private final static SimpleDateFormat sTsDateFormat
            = new SimpleDateFormat("yyyyMMdd", Locale.CHINA);
    // set default start date to 1990-01-01: year - 1900, month - 1, day = day - 1
    private final static Date sDefaultStartDate = new Date(90, 0, 0);
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

    private static String toTsCode(String netEaseCode) {
        String tsCode;
        if (netEaseCode.startsWith("1")) {
            tsCode = netEaseCode.substring(1) + ".SZ";
        } else {
            tsCode = netEaseCode.substring(1) + ".SH";
        }
        return tsCode;
    }
/*
注：日期都填YYYYMMDD格式，比如20181010
输出参数
名称	类型	描述
ts_code	str	股票代码
trade_date	str	交易日期
open	float	开盘价
high	float	最高价
low	float	最低价
close	float	收盘价
pre_close	float	昨收价
change	float	涨跌额
pct_chg	float	涨跌幅 （未复权，如果是复权请用 通用行情接口 ）
vol	float	成交量 （手）
amount	float	成交额 （千元）
* */
    private static final Map<String, String> sTushareFieldsMap = new HashMap<>();
    static {
        sTushareFieldsMap.put("trade_date", "date");
        sTushareFieldsMap.put("ts_code", "code");
        sTushareFieldsMap.put("open", "open");
        sTushareFieldsMap.put("high", "high");
        sTushareFieldsMap.put("low", "low");
        sTushareFieldsMap.put("close", "close");
        sTushareFieldsMap.put("pre_close", "yclose");
        sTushareFieldsMap.put("change", "change");
        sTushareFieldsMap.put("pct_chg", "pchg");
        sTushareFieldsMap.put("vol", "volume");
        sTushareFieldsMap.put("amount", "amount");
    }

    private static Map<String, Integer> getTushareIndexMap(JSONArray fieldsArray)
            throws  JSONException{
        Map<String, Integer> headerIndexMap = new HashMap<>();
        for (int i = 0; i < fieldsArray.length(); i++) {
            String field = fieldsArray.getString(i);
            String mapName = sTushareFieldsMap.get(field);
            headerIndexMap.put(mapName, i);
        }
        return headerIndexMap;
    }

    private static String buildDailyRequest(String tsCode, Date startDate, Date endDate)
            throws  JSONException{
        JSONObject paramsObj = new JSONObject();
        paramsObj.put("ts_code", tsCode);
        paramsObj.put("start_date", sTsDateFormat.format(startDate));
        paramsObj.put("end_date", sTsDateFormat.format(endDate));
        JSONObject bodyObj = new JSONObject();
        bodyObj.put("api_name", "daily");
            bodyObj.put("token", "55189c3a5c7c0cf86a7b738f5e3537414f3c250f072b7005dfbd70b6");
        bodyObj.put("params", paramsObj);
        return bodyObj.toString();
    }

    static void updateHistoryDatabase(String netEaseCode, Realm realm, Date endDate) {
        Date lastRecordDate;
        float lastMcap = 0;
        RealmResults<HistoryDayQuote> results = realm.where(HistoryDayQuote.class)
                .sort("date", Sort.ASCENDING).findAll();
        if (results.size() <= 0) {
            lastRecordDate = sDefaultStartDate;
        } else {
            int date = results.max("date").intValue();
            lastRecordDate = Utils.getDateFromIDate(date);
            lastMcap = results.get(results.size() - 1).getMcap();
        }
        long deltaMills = endDate.getTime() - lastRecordDate.getTime();
        if (deltaMills < Utils.MILLIS_PER_DAY) {
            return;
        }
        Date startDate = new Date(lastRecordDate.getTime() + Utils.MILLIS_PER_DAY);
        String tsCode = toTsCode(netEaseCode);
        try {
            String json = buildDailyRequest(tsCode, startDate, endDate);
            RequestBody body = RequestBody.create(JSON, json);
            Request request = new Request.Builder()
                    .url("http://api.tushare.pro")
                    .post(body)
                    .build();
            OkHttpClient client = new OkHttpClient();

            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                String bodyString = response.body().string();
                JSONObject resultObj = new JSONObject(bodyString);
                int resultCode = Integer.valueOf(resultObj.getString("code"));
                if (resultCode != 0) {
                    return;
                }
                JSONObject resultData = resultObj.getJSONObject("data");
                JSONArray fieldsArray = resultData.getJSONArray("fields");
                Map<String, Integer> fieldMap = getTushareIndexMap(fieldsArray);
                JSONArray itemsArray = resultData.getJSONArray("items");
                realm.beginTransaction();
                for (int i = 0; i < itemsArray.length(); i++) {
                    JSONArray item = itemsArray.getJSONArray(i);
                    HistoryDayQuote quote = new HistoryDayQuote(item, fieldMap, lastMcap);
                    if (!quote.isQualified()) {
                        continue;
                    }
                    realm.insertOrUpdate(quote);
                }
                realm.commitTransaction();
            }
        } catch (NullPointerException e) {
            Log.e(TAG, "TuShare update " + netEaseCode + " history_data NullPointerException fail:", e);
        } catch (JSONException e) {
            Log.e(TAG, "TuShare update " + netEaseCode + " history_data JSONException fail", e);
        } catch (IOException e) {
            Log.e(TAG, "TuShare update  " + netEaseCode + " history_data IOException fail", e);
        }
    }

    private static String buildStockInfoRequest()
            throws  JSONException{
        JSONObject paramsObj = new JSONObject();
        paramsObj.put("exchange", "");
        paramsObj.put("list_status", "L");
        paramsObj.put("fields", "ts_code, symbol, name, area, industry, market, list_date,");
        JSONObject bodyObj = new JSONObject();
        bodyObj.put("api_name", "stock_basic");
        bodyObj.put("token", "55189c3a5c7c0cf86a7b738f5e3537414f3c250f072b7005dfbd70b6");
        bodyObj.put("params", paramsObj);
        return bodyObj.toString();
    }

    private static final Map<String, String> sStockInfoMap = new HashMap<>();
    static {
        sStockInfoMap.put("ts_code", "ts_code");
        sStockInfoMap.put("symbol", "symbol");
        sStockInfoMap.put("name", "name");
        sStockInfoMap.put("area", "area");
        sStockInfoMap.put("industry", "industry");
        sStockInfoMap.put("market", "market");
        sStockInfoMap.put("list_date", "list_date");
    }

    private static Map<String, Integer> getStockInfoMap(JSONArray fieldsArray)
            throws  JSONException{
        Map<String, Integer> fieldMap = new HashMap<>();
        for (int i = 0; i < fieldsArray.length(); i++) {
            String field = fieldsArray.getString(i);
            String mapName = sStockInfoMap.get(field);
            fieldMap.put(mapName, i);
        }
        return fieldMap;
    }

    static void updateStockInfoRealm() {
        try {
            String json = buildStockInfoRequest();
            RequestBody body = RequestBody.create(JSON, json);
            Request request = new Request.Builder()
                    .url("http://api.tushare.pro")
                    .post(body)
                    .build();
            OkHttpClient client = new OkHttpClient();

            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                String bodyString = response.body().string();
                JSONObject resultObj = new JSONObject(bodyString);
                int resultCode = Integer.valueOf(resultObj.getString("code"));
                if (resultCode != 0) {
                    return;
                }
                JSONObject resultData = resultObj.getJSONObject("data");
                JSONArray fieldsArray = resultData.getJSONArray("fields");
                Map<String, Integer> fieldMap = getStockInfoMap(fieldsArray);
                JSONArray itemsArray = resultData.getJSONArray("items");

                RealmConfiguration stockInfoConfig = new RealmConfiguration.Builder()
                        .name("stock_info.realm")
                        .deleteRealmIfMigrationNeeded()
                        .build();
                Realm realm = Realm.getInstance(stockInfoConfig);
                realm.beginTransaction();
                for (int i = 0; i < itemsArray.length(); i++) {
                    JSONArray item = itemsArray.getJSONArray(i);
                    StockInfo si = new StockInfo(item, fieldMap);
                    realm.insertOrUpdate(si);
                }
                realm.commitTransaction();
                realm.close();
                if(!Realm.compactRealm(stockInfoConfig)) {
                    Log.w(TAG, "After NetEase update stock info, compact realm fail");
                }
            }
        } catch (NullPointerException e) {
            Log.e(TAG, "TuShare update stock_basic NullPointerException fail:", e);
        } catch (JSONException e) {
            Log.e(TAG, "TuShare update stock_basic JSONException fail:", e);
        } catch (IOException e) {
            Log.e(TAG, "TuShare update stock_basic IOException fail:", e);
        }
    }
}
